from flask import Blueprint, request, jsonify, send_file
from services.document_service import DocumentService
from services.text_splitter import SplitConfig
from models.document import Document
import pandas as pd
import json
from werkzeug.utils import secure_filename
import os

document_bp = Blueprint('document', __name__)
document_service = DocumentService()

def get_safe_filename(filename):
    """
    安全地处理文件名，保留中文字符并移除不安全字符。
    
    Args:
        filename (str): 原始文件名
        
    Returns:
        str: 处理后的安全文件名，保留原扩展名
    """
    # 获取文件名和扩展名
    name, ext = os.path.splitext(filename)
    # 替换不安全的字符为下划线，但保留中文字符
    safe_name = ''.join(c for c in name if c.isalnum() or c.isspace() or c in '.-_()[]{}中文' or '\u4e00' <= c <= '\u9fff')
    # 组合新的文件名
    return safe_name + ext

@document_bp.route('/upload', methods=['POST'])
def upload_document():
    """
    处理文档上传请求，支持结构化数据的处理和文本分割配置。
    
    Form Parameters:
        file: 上传的文件对象
        knowledge_id (str): 知识库ID
        strategy (str, optional): 分割策略，默认为'paragraph'
        chunk_size (int, optional): 分块大小，默认为1000
        chunk_overlap (int, optional): 分块重叠大小，默认为200
        document_columns (json, optional): 文档列映射配置
        metadata_columns (json, optional): 元数据列映射配置
    
    Returns:
        JSON: 处理结果
            成功: {"success": true, ...处理结果}
            失败: {"error": "错误信息"}, 状态码
    """
    try:
        if 'file' not in request.files:
            return jsonify({"error": "未提供文件"}), 400
            
        file = request.files['file']
        if file.filename == '':
            return jsonify({"error": "未选择文件"}), 400
            
        # 获取knowledge_id参数
        knowledge_id = request.form.get('knowledge_id')
        if not knowledge_id:
            return jsonify({"error": "未提供知识库ID"}), 400

        # 安全处理文件名，保留中文字符
        filename = get_safe_filename(file.filename)
        file_content = file.read()  # 只读取一次文件内容

        # 获取分割配置
        split_config = SplitConfig(
            strategy=request.form.get('strategy', 'paragraph'),
            chunk_size=int(request.form.get('chunk_size', 1000)),
            chunk_overlap=int(request.form.get('chunk_overlap', 200))
        )

        # 获取结构化数据列映射（如果有）
        document_columns = request.form.get('document_columns')
        metadata_columns = request.form.get('metadata_columns')
        
        if document_columns:
            document_columns = json.loads(document_columns)
        if metadata_columns:
            metadata_columns = json.loads(metadata_columns)
        
        # 处理文档
        result = document_service.process_document(
            file_content=file_content,  # 传递已读取的内容
            filename=filename,
            knowledge_id=int(knowledge_id),
            split_config=split_config,
            document_columns=document_columns,
            metadata_columns=metadata_columns
        )
        
        return jsonify(result)
        
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@document_bp.route('/preview', methods=['POST'])
def preview_document():
    """
    预览上传的结构化文档（CSV、Excel）的前5行数据。
    
    Form Parameters:
        file: 上传的文件对象（支持.csv、.xlsx、.xls格式）
    
    Returns:
        JSON: 预览数据
            成功: {
                "columns": [列名列表],
                "preview": [前5行数据记录]
            }
            失败: {"error": "错误信息"}, 状态码
    """
    if 'file' not in request.files:
        return jsonify({"error": "未提供文件"}), 400
        
    file = request.files['file']
    if file.filename == '':
        return jsonify({"error": "文件名为空"}), 400
        
    try:
        # 获取文件扩展名
        extension = file.filename.rsplit('.', 1)[1].lower()
        
        # 读取文件预览
        if extension == 'csv':
            df = pd.read_csv(file, nrows=5)
        elif extension in ['xlsx', 'xls']:
            df = pd.read_excel(file, nrows=5)
        else:
            return jsonify({"error": "不支持的文件格式"}), 400
            
        return jsonify({
            "columns": df.columns.tolist(),
            "preview": df.head().to_dict('records')
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@document_bp.route('/', methods=['GET'])
def get_documents():
    """
    获取指定知识库下的文档列表。
    
    Query Parameters:
        knowledge_id (str): 知识库ID
    
    Returns:
        JSON: 文档列表
            成功: [文档对象列表]
            失败: {"error": "错误信息"}, 状态码
    """
    try:
        knowledge_id = request.args.get('knowledge_id')
        if not knowledge_id:
            return jsonify({"error": "未提供知识库ID"}), 400
            
        documents = document_service.get_documents(int(knowledge_id))
        return jsonify(documents)
        
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@document_bp.route('/<int:document_id>', methods=['DELETE'])
def delete_document(document_id):
    """
    删除指定ID的文档。
    
    Args:
        document_id (int): 文档ID
    
    Returns:
        JSON: 删除结果
            成功: {"success": true, ...删除结果}
            失败: {"error": "错误信息"}, 状态码
    """
    try:
        result = document_service.delete_document(document_id)
        return jsonify(result)
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@document_bp.route('/collections', methods=['GET'])
def get_collections():
    """
    获取文档集合列表，默认返回前20条记录。
    
    Returns:
        JSON: 集合列表和总数
            成功: {
                "collections": [集合列表],
                "total": 总数量
            }
            失败: {"error": "错误信息"}, 状态码
    """
    try:
        collections = document_service.get_collections(limit=20)
        return jsonify({
            "collections": collections,
            "total": len(collections)
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@document_bp.route('/download/<int:document_id>', methods=['GET'])
def download_document(document_id):
    """
    下载指定ID的文档。
    
    Args:
        document_id (int): 文档ID
    
    Returns:
        File: 文件下载响应
            成功: 文件流，带有合适的mimetype和下载文件名
            失败: {"error": "错误信息"}, 状态码
            
    Note:
        - 使用send_file处理文件下载
        - 自动设置正确的mimetype
        - 支持自定义下载文件名
    """
    try:
        ret = document_service.download_document(document_id)
        if not ret:
            return jsonify({"error": "下载文件失败"}), 500

        file_obj, filename, mimetype = ret
        return send_file(
            file_obj,
            as_attachment=True,
            download_name=filename,
            mimetype=mimetype
        )
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@document_bp.route('/create', methods=['POST'])
def create_empty_document():
    """
    创建一个空文档，文件名称为 "空文档"，minio_patch 为 None.
    
    Form Parameters:
        knowledge_id (str): 知识库ID
    
    Returns:
        JSON: 创建结果
            成功: {"success": true, ...创建结果}
            失败: {"error": "错误信息"}, 状态码
    """
    try:
        knowledge_id = request.form.get('knowledge_id')
        if not knowledge_id:
            return jsonify({"error": "未提供知识库ID"}), 400

        # 使用 document_service 创建空文档
        result = document_service.create_empty_document(
            knowledge_id=int(knowledge_id)
        )
        return jsonify(result)
    except Exception as e:
        return jsonify({"error": str(e)}), 500